/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package fr.sorbonne.inf5.yams.controleur;

import fr.sorbonne.inf5.yams.exceptions.AccessDataException;
import fr.sorbonne.inf5.yams.exceptions.CombinaisonNotFoundException;
import fr.sorbonne.inf5.yams.exceptions.DeNotRunException;
import fr.sorbonne.inf5.yams.exceptions.JoueurNotFoundException;
import fr.sorbonne.inf5.yams.exceptions.TourPlayerOverException;
import fr.sorbonne.inf5.yams.model.AbstractIA;
import fr.sorbonne.inf5.yams.model.AbstractJoueur;
import fr.sorbonne.inf5.yams.model.De;
import fr.sorbonne.inf5.yams.model.LignePalmares;
import fr.sorbonne.inf5.yams.model.Score;
import fr.sorbonne.inf5.yams.model.Yams;
import fr.sorbonne.inf5.yams.model.combinaison.Combinaison;
import fr.sorbonne.inf5.yams.vue.VueApplication;
import fr.sorbonne.inf5.yams.vue.VueCombinaisons;
import fr.sorbonne.inf5.yams.vue.VueDes;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Classe en charge du deroulement
 * du jeu
 * @author Dubos Romain
 * @author Oukherfellah Riad
 */
public class ControleurJeu implements ActionListener {

    private VueApplication vue;
    private Yams model;
    private VueDes vueDes;
    private VueCombinaisons vueCombi;

    /**
     * Constructeur
     * @param pVue vue de l'application
     * @param pModel modèle de l'application
     */
    public ControleurJeu(VueApplication pVue, Yams pModel) {
        this.vue = pVue;
        this.model = pModel;
        this.vueDes = this.vue.renvoyerVueDes();
        this.vueCombi = this.vue.renvoyerVueCombinaisons();
    }

    public void actionPerformed(ActionEvent e) {
        String event = e.getActionCommand();
        Object eventObject = e.getSource();
        List<De> des = null;
        Integer faceNumerique = 0;
        String image = null;
        De de = null;

        //LANCER LES DES
        if (event.equals(VueApplication.LANCER)) {
            try {
                des = model.lancerDes();

                //Dé numero 1
                de = des.get(0);
                this.changerAffichageDe(1, de);

                //Dé numero 2
                de = des.get(1);
                this.changerAffichageDe(2, de);

                //Dé numero 3
                de = des.get(2);
                this.changerAffichageDe(3, de);

                //Dé numero 4
                de = des.get(3);
                this.changerAffichageDe(4, de);

                //Dé numero 5
                de = des.get(4);
                this.changerAffichageDe(5, de);

                this.chargerPrevisionCombi();

            } catch (TourPlayerOverException ex) {
                //Le joueur a déjà fait ses 3 lancer
                vue.afficherMessageInfo(VueApplication.T2, VueApplication.M2);
            } catch (DeNotRunException ex) {
                vue.afficherMessageErreur(VueApplication.T6, VueApplication.M6);
            } catch (CombinaisonNotFoundException ex) {
                vue.afficherMessageErreur(VueApplication.T6, VueApplication.M6);
            }
        }

        //Clique sur Dé numero 1
        if (event.equals(VueDes.D1)) {
            des = model.renvoyerDe();
            de = des.get(0);
            this.gestionClickDe(de, 1);

        }

        //Clique sur Dé numero 2
        if (event.equals(VueDes.D2)) {
            des = model.renvoyerDe();
            de = des.get(1);

            this.gestionClickDe(de, 2);
        }

        //Clique sur Dé numero 3
        if (event.equals(VueDes.D3)) {
            des = model.renvoyerDe();
            de = des.get(2);

            this.gestionClickDe(de, 3);
        }

        //Clique sur Dé numero 4
        if (event.equals(VueDes.D4)) {
            des = model.renvoyerDe();
            de = des.get(3);

            this.gestionClickDe(de, 4);

        }

        //Clique sur Dé numero 5
        if (event.equals(VueDes.D5)) {
            des = model.renvoyerDe();
            de = des.get(4);

            this.gestionClickDe(de, 5);

        }

        //Validation combinaison "UN"
        if (event.equals(VueCombinaisons.UN)) {
            this.validerCombi(VueCombinaisons.UN);
        }

        //Validation combinaison "DEUX"
        if (event.equals(VueCombinaisons.DEUX)) {
            this.validerCombi(VueCombinaisons.DEUX);
        }

        //Validation combinaison "TROIS"
        if (event.equals(VueCombinaisons.TROIS)) {
            this.validerCombi(VueCombinaisons.TROIS);
        }

        //Validation combinaison "QUATRE"
        if (event.equals(VueCombinaisons.QUATRE)) {
            this.validerCombi(VueCombinaisons.QUATRE);
        }

        //Validation combinaison "CINQ"
        if (event.equals(VueCombinaisons.CINQ)) {
            this.validerCombi(VueCombinaisons.CINQ);
        }

        //Validation combinaison "SIX"
        if (event.equals(VueCombinaisons.SIX)) {
            this.validerCombi(VueCombinaisons.SIX);
        }

        //Validation combinaison "INF"
        if (event.equals(VueCombinaisons.INF)) {
            this.validerCombi(VueCombinaisons.INF);
        }

        //Validation combinaison "SUP"
        if (event.equals(VueCombinaisons.SUP)) {
            this.validerCombi(VueCombinaisons.SUP);
        }

        //Validation combinaison "PETITE"
        if (event.equals(VueCombinaisons.PETITE)) {
            this.validerCombi(VueCombinaisons.PETITE);
        }

        //Validation combinaison "GRANDE"
        if (event.equals(VueCombinaisons.GRANDE)) {
            this.validerCombi(VueCombinaisons.GRANDE);
        }

        //Validation combinaison "FULL"
        if (event.equals(VueCombinaisons.FULL)) {
            this.validerCombi(VueCombinaisons.FULL);
        }

        //Validation combinaison "CARRE"
        if (event.equals(VueCombinaisons.CARRE)) {
            this.validerCombi(VueCombinaisons.CARRE);
        }

        //Validation combinaison "YAM"
        if (event.equals(VueCombinaisons.YAM)) {
            this.validerCombi(VueCombinaisons.YAM);
        }

    }

    /**
     * Modifit l'image d'un dé selon sa face réelle
     * @param numDe numero du dé
     * @param de dé a changer
     * @throws DeNotRunException
     */
    public void changerAffichageDe(int numDe, De de) throws DeNotRunException {
        Integer faceNumerique = (Integer) de.getFaceCourante().retournerFace();
        vueDes.changerDe(vueDes.renvoyerImageCorrespondante(faceNumerique, model.isBloque(de)), numDe);
    }

    /**
     * Gestion du clique sur un dé
     * @param de
     * @param numDe
     */
    public void gestionClickDe(De de, int numDe) {
        Integer faceNumerique = 0;
        try {
            faceNumerique = (Integer) de.getFaceCourante().retournerFace();
            if (!model.isBloque(de)) {
                model.bloquerDe(de);
            } else {
                model.deBloquerDe(de);
            }
            vueDes.changerDe(vueDes.renvoyerImageCorrespondante(faceNumerique, model.isBloque(de)), numDe);

        } catch (DeNotRunException ex) {
            //Lancer avant de valider
            vue.afficherMessageInfo(VueApplication.T3, VueApplication.M3);
        }
    }

    /**
     * Valide la combinaison et lance la suite
     */
    public void validerCombi(String pCombi) {
        try {
            model.validerCombinaison(model.renvoyerCombinaison(pCombi));
            if (model.retournerJoueurCourant() instanceof AbstractIA) {
                vue.afficherScoreIA(String.valueOf(model.renvoyerScore().scoreFinal()));
            }
            model.changerJoueur();
            vueDes.initialiseDesA1();
            AbstractJoueur jCourant = (AbstractJoueur) model.retournerJoueurCourant();
            vueCombi.changeJoueurCourant(jCourant.getNom());

            Score score = model.renvoyerScore(jCourant);
            Map<Combinaison, Integer> combiScore = score.renvoyerScore();
            Set<Combinaison> combis = combiScore.keySet();
            List<Boolean> combiValide = new ArrayList<Boolean>();
            for (Combinaison c : combis) {
                combiValide.add(!score.combinaisonLibre(c));
            }
            vueCombi.griserCombisValides(combiValide);
            Collection<Integer> scoreCombi = combiScore.values();
            Object[] scores = scoreCombi.toArray();
            vueCombi.chargerNumValidationPrec(scores);
            vueCombi.chargerScores(String.valueOf(score.scoreFinal()),
                    String.valueOf(score.scorePartieHaute()),
                    String.valueOf(score.scorePartieCentrale()),
                    String.valueOf(score.scorePartieBasse()));
            if (jCourant instanceof AbstractIA) {
                String combiValider = ((AbstractIA) jCourant).jouer();
                validerCombi(combiValider);
            }

            if (model.partieTermine()) {
                vue.afficherMessageInfo(VueApplication.T7, VueApplication.M7);
                model.ajouterLignePalmares(new LignePalmares(jCourant.getNom(), score.scoreFinal()));
                try {
                    model.sauvegarderPalmares();
                } catch (AccessDataException ex) {
                    vue.afficherMessageErreur(VueApplication.T8, VueApplication.M8);
                }
                vueDes.initialiseDesA1();
                vue.griserVue();
            }

        } catch (CombinaisonNotFoundException ex) {
            vue.afficherMessageErreur(VueApplication.T6, VueApplication.M6);
        } catch (DeNotRunException ex) {
            //Lancer avant de valider
            vue.afficherMessageInfo(VueApplication.T3, VueApplication.M3);
        } catch (JoueurNotFoundException ex) {
            vue.afficherMessageErreur(VueApplication.T6, VueApplication.M6);
        }

    }

    /**
     * Charge les previsions des scores des combinaison
     * ainsi que le joueur courant et le nb de lancer
     * @throws DeNotRunException
     * @throws CombinaisonNotFoundException
     */
    public void chargerPrevisionCombi() throws DeNotRunException, CombinaisonNotFoundException {

        Map<Combinaison, Integer> previsions = model.calculCombinaisonInfo();

        List<String> prevString = new ArrayList<String>();

        //Combinaison
        prevString.add(String.valueOf(previsions.get(model.renvoyerCombinaison(VueCombinaisons.UN))));
        prevString.add(String.valueOf(previsions.get(model.renvoyerCombinaison(VueCombinaisons.DEUX))));
        prevString.add(String.valueOf(previsions.get(model.renvoyerCombinaison(VueCombinaisons.TROIS))));
        prevString.add(String.valueOf(previsions.get(model.renvoyerCombinaison(VueCombinaisons.QUATRE))));
        prevString.add(String.valueOf(previsions.get(model.renvoyerCombinaison(VueCombinaisons.CINQ))));
        prevString.add(String.valueOf(previsions.get(model.renvoyerCombinaison(VueCombinaisons.SIX))));
        prevString.add(String.valueOf(previsions.get(model.renvoyerCombinaison(VueCombinaisons.SUP))));
        prevString.add(String.valueOf(previsions.get(model.renvoyerCombinaison(VueCombinaisons.INF))));
        prevString.add(String.valueOf(previsions.get(model.renvoyerCombinaison(VueCombinaisons.CARRE))));
        prevString.add(String.valueOf(previsions.get(model.renvoyerCombinaison(VueCombinaisons.FULL))));
        prevString.add(String.valueOf(previsions.get(model.renvoyerCombinaison(VueCombinaisons.PETITE))));
        prevString.add(String.valueOf(previsions.get(model.renvoyerCombinaison(VueCombinaisons.GRANDE))));
        prevString.add(String.valueOf(previsions.get(model.renvoyerCombinaison(VueCombinaisons.YAM))));

        vueCombi.chargerPrevison(prevString);

        //Scores
        vueCombi.chargerScores(String.valueOf(model.renvoyerScore().scoreFinal()),
                String.valueOf(model.renvoyerScore().scorePartieHaute()),
                String.valueOf(model.renvoyerScore().scorePartieCentrale()),
                String.valueOf(model.renvoyerScore().scorePartieBasse()));


        //Nombre de lancer restant
        vueCombi.changeNombreLancer(String.valueOf(model.getNbLancerRestant()));

        //Joueur courant
        vueCombi.changeJoueurCourant(model.retournerJoueurCourant().getNom());

    }
}
